
// ===============================================================================================================
// -*- C++ -*-
//
// ObjectPool.hpp - Template class for a memory pool of objects.
//
// Copyright (c) 2011 Guilherme R. Lampert
// guilherme.ronaldo.lampert@gmail.com
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#ifndef __OBJECT_POOL_HPP__
#define __OBJECT_POOL_HPP__

#include <Common.hpp>

///
/// A memory pool that keeps a list of pre-allocated and recycled memory blocks for fast allocations.
/// Using a poll will consume some memory by itself, but it will bring a good speed boost to allocations as a reward.
/// \note The ObjectPool is NOT thread safe, so for multy-thread applications you should use your own locking mechanisms.
///
template<typename T> class ObjectPool {

public:

	typedef T ElementType;
	typedef size_t SizeType;
	typedef ptrdiff_t DifferenceType;

	// Construction / Destruction:

	 ObjectPool(void);
	~ObjectPool(void);

	/// Allocates memory that can hold an object of type ElementType (T).
	/// If out of memory, returns a null pointer. Amortized O(1).
	T * Allocate(void);

	/// Deallocates a chunk of memory. Note that the destructor for 'object' is NOT called.
	/// If 'object' is null, nothing is done. O(N).
	/// \param [in] object: A memory chunk that was returned by ObjectPool::Allocate().
	void Free(T * object);

	/// Frees every memory block of this pool.
	/// This function invalidates any pointers previously returned by allocation functions of this memory pool.
	/// \return The number of blocks destroyed.
	SizeType Purge(void);

	/// Return the number of active chunks (objects) this pool has. (User objects).
	SizeType NumberOfObjects(void) const;

private:

	///
	/// Internal representation of a memory chunk allocated by the pool.
	///
	struct Chunk {

		struct Chunk * next; ///< Next memory chunk in the linked list
	};

	///
	/// This control the number of memory allocations performed by the pool.
	/// The bigger LOGSIZE_MAX is, the less allocations will be made, and more memory will be requested on each.
	///
	enum { LOGSIZE_MIN = 0, LOGSIZE_MAX = 32000 };

private:

	struct Chunk * list;  ///< List of allocated blocks
	struct Chunk * trash; ///< List of deleted chunks

	SizeType chunkSize; ///< Size of a memory chunk (in bytes)
	SizeType logSize;   ///< Log_2 of number of chunks in a block
	SizeType bytesLeft; ///< Number of bytes left in a block

	SizeType chunkCount; ///< Current number of active user chunks (objects) this pool has. (Chunks returned by ObjectPool::Allocate() only)
};

#include <ObjectPool.inl>

#endif // __OBJECT_POOL_HPP__